52 re 模块

452次阅读
没有评论

共计 8165 个字符,预计需要花费 21 分钟才能阅读完成。

引入

正则表达式是匹配字符串的强大工具, 在每个编程语言中都有正则表达式的概念, 利用正则表达式, 我们从返回的页面内容中提取想要的内容就变的比较方便了

1. 什么是 re 模块

  • re 模块是 Python 内置的模块

2. 什么是正则

  • 正则表达式是对字符串操作的一种 逻辑 (规则), 就是事先定义好一些特定的字符组合, 组成一个 "规则字符串 ", 然后使用这个 " 规则字符串" 来对字符串进行过滤
  • Python 中通过内置的 re 模块来使用正则表达式, 它提供了所有正则表达式的功能

3. 正则表达式的大致匹配过程

  • 定义一个"规则字符串", 然后依次与文本中的字符进行对比
  • 如果 每一个字符 都能匹配, 那么就匹配成功, 否则匹配失败
  • 如果表达式中有 量词 或者 边界, 这个过程会稍微有一些不同

4. 正则小示例

  • 比如我们描述四条腿的东西 (规则字符串), 我们可能会想到的有四条腿的动物, 桌子和椅子等等
  • 比如我们描述 条腿的东西并且是活的, 我们可能会想到人类, 猴子, 鸟, 袋鼠, 鸡么等等

52 re 模块

5. 常用正则表达式表

模式 描述
\w 匹配字母数字及下划线
\W 匹配非字母数字下划线
\s 匹配任意空白字符,等价于[\t,\n,\r,\f]
\S 匹配任意非空字符
\d 匹配任意数字,等价于[0-9]
\D 匹配任意非数字
\A 匹配以 xx 字符串开始
\Z 匹配 xx 字符串结束,如果是存在换行,只匹配到换行前的结束字符串
\z 匹配 xx 字符串结束
\G 匹配最后匹配完成的位置
\n 匹配一个换行符
\t 匹配一个制表符
^ 匹配字符串的开头
$ 匹配字符串的末尾
. 匹配任意字符, 除了换行符, 当 re.DOTALL 标记被指定时, 则可以匹配包括换行符的任意字符
[...] 用来表示一组字符,单独列出:[amk] 匹配 'a','m' 或 'k'
[^...] 不在 [] 中的字符:[^abc] 匹配除了 a,b,c 之外的字符
* 匹配 0 个或多个的表达式
+ 匹配 1 个或多个的表达式
? 匹配 0 个或 1 个由前面的正则表达式定义的片段,非贪婪方式
{n} 精确匹配 n 个前面表达式。
{n,m} 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
alb 匹配 a 或 b
() 匹配括号内的表达式,也表示一个组

ps : [...] 讲解 : []所有的特殊字符在字符集中都失去其原有的特殊含义, 在字符集中如果要使用 ]-^,可以在前面加上 反斜杠 ,或把]- 放在第一个字符,把 ^ 放在非第一个字符

更多正则表达式 : https://www.jb51.net/tools/regexsc.htm

一. 普通字符和元字符

正则表达式就是由一些普通字符和元字符组成的

  • 普通字符就是 字母和数字
  • 元字符就是具有 特殊意义的字符, 常用于表单验证

二. 正则边界(定位字符)

  • ^ : 会匹配字符串或者行的 起始 位置, 在 [] 中表示 ''非''(!)
  • $ : 会匹配字符串或行的 结束 位置 (在 \n 之前)
  • ^,$ 一起则表示 精确匹配 包裹在两个符号之间的字符串
  • \A : 指定匹配必须出现在字符串的开头(忽略 Multiline 选项)
  • \Z : 指定匹配必须出现在字符串的结尾或字符串结尾的 \n 之前(忽略 Multiline 选项)

三. 量词

  • : 重复零次或更多(>=0)

  • : 重复一次或更多次(>=1)

  • : 重复零次或一次(0 || 1)

  • {} : 重复多少次的意思 可以有多少个

四. 常用的功能函数

函数 说明
re.match() 从字符串的起始位置匹配, 匹配成功, 返回一个匹配的对象, 否则返回 None
re.search() 扫描整个字符串并返回第一个成功的匹配
re.findall() 在字符串中找到正则表达式所匹配的所有子串, 并返回一个列表, 如果没有找到匹配的, 则返回空列表
re.split() 将一个字符串按照正则表达式匹配结果进行分割, 返回列表类型
re.finditer() 在字符串中找到正则表达式所匹配的所有子串, 并把它们作为一个迭代器返回
re.sub() 把字符串中所有匹配正则表达式的地方替换成新的字符串
re.complie() 将正则表达式传入, 返回一个匹配对象, 一般与其他方法组合使用

五. 正则使用示例

💠一对一匹配

print("hello".replace("llo","ooo"))  # heooo
print("hello".find("abcd"))  # -1 (找不到返回 -1)
print("hello".find("he"))    # 0

💠正则匹配

  • \w\W
import re

print(re.findall("\w","ab* 12$ _"))  # ['a', 'b', '1', '2', '_']
print(re.findall("\W","ab* 12$ _"))  # ['*', '','$',' ']
  • \s\S
print(re.findall("\s","ab* 12$ _ "))  # ['',' ',' ']
print(re.findall("\S","ab* 12$ _ "))  # ['a', 'b', '*', '1', '2', '$', '_']
  • \d\D
print(re.findall("\d","ab* 12$ _"))  # ['1', '2']
print(re.findall("\D","ab* 12$ _"))  # ['a', 'b', '*', '','$',' ','_']
  • \A\Z
print(re.findall("\Aab","ab* 12$ _"))  # ['ab']
print(re.findall("\Aaa","ab* 12$ _"))  # [] 没匹配到为空
print(re.findall("_\Z","ab* 12$ _"))   # ['_']
print(re.findall("0\Z","ab* 12$ _"))   # [] 没匹配到为空
  • \t\n
print(re.findall("\t","ab* 12$ \t_"))    # ['\t']
print(re.findall("\n","ab* 12$ \n_"))    # ['\n']

🔰"\s" 可以匹配 "\t" 和 "\n"
print(re.findall("\s","ab* \t12$ _\n"))  # ['','\t',' ','\n']
  • ^\$
print(re.findall("^ab","ab* 12$ _"))   # ['ab']
print(re.findall("_$","ab* 12$ _\n"))  # ['_']

💠重复匹配

  • : 匹配一个任意字符
print(re.findall("a.b","a&b"))  # ['a&b']
print(re.findall("a.b","a2b"))  # ['a2b']
print(re.findall("a.b","acb"))  # ['acb']
print(re.findall("a.b","a b"))  # ['a b']
print(re.findall("a.b","a\tb")) # ['\t']
print(re.findall("a.b","a\nb")) # [] (换行符匹配不到, 匹配为空)
print(re.findall("a.b","a b a*b abb a_b"))  # ['a b', 'a*b', 'abb', 'a_b']
print(re.findall("a.b","a\nb",re.S))        # ['a\nb'] (加入参数, 包含换行)
print(re.findall("a.b","a\nb",re.DOTALL))   # ['a\nb'] (同上效果一样)
  • : 匹配零个或多个
print(re.findall("a*","aaaa aa"))        # ['aaaa', '','aa',''] (零个或多个 a)
print(re.findall("ab*","abab aa"))       # ['ab', 'ab', 'a', 'a'] (一个 a 零个或多个 b)
print(re.findall("a*b","ababaaaba aa"))  # ['ab', 'ab', 'aaab'] (零个或多个 a 一个 b)
print(re.findall("ab*","bbbbbbbb"))      # [] (没有匹配到一个 a 零个或多个 b)
  • : 匹配零个或一个
print(re.findall("ab?","a"))     # ['a']
print(re.findall("ab?","abbb"))  # ['ab']
  • : 匹配一个或多个
print(re.findall("a+","bbb"))    # []
print(re.findall("a+","ab"))     # ['a']
print(re.findall("ab+","ab"))    # ['ab']
print(re.findall("ab+","abbb"))  # ['abbb']
  • {n,m} : 匹配 n~m 之间个
print(re.findall("a{9}","aaaa"))     # [] (匹配 9 个 b, 没有)
print(re.findall("a{3}","aaaa"))     # ['aaa']
print(re.findall("a{2}","aaaa"))     # ['aa', 'aa']
print(re.findall("ab{2}","aabbb"))   # ['abb']
print(re.findall("ab{2,6}","abbb"))  # ['abbb'] (一个 a,2~6 个 b)
print(re.findall("ab{1,}","abbb"))   # ['abbb'] (相当于 ab+)
print(re.findall("ab{0,}","abbb"))   # ['abbb'] (相当于 ab*)
  • [] : 放一组字符, 逐个匹配
print(re.findall("a[*1_c-]b","a*ba1b a_baaba-b"))     # ['a*b', 'a1b', 'a_b', 'a-b']
print(re.findall("a[^*1c-]b","a*ba1b a_baab"))        # ['a_b', 'aab'] (匹配非 [] 内的字符)
print(re.findall("a[0-9]b","a*ba1b a3baa2b"))         # ['a1b', 'a3b', 'a2b'] (0~9)
print(re.findall("a[a-z]b","a*banb apbaaob"))         # ['anb', 'apb', 'aob'] (a~z)
print(re.findall("a[a-zA-Z0-9]b","a*banb aPbaa7b"))   # ['anb', 'aPb', 'a7b']
print(re.findall("a[^a-zA-Z0-9]b","a*banb aPbaa7b"))  # ['a*b'] (非 a~z,A~Z,0~9)
  • () : 分组
print(re.findall('ab+','ababab123')) 
# ['ab', 'ab', 'ab']
print(re.findall('(ab)+123','ababab123')) 
# ['ab'],匹配到末尾的 ab123 中的 ab
print(re.findall('(?:ab)+123','ababab123')) 
# findall 的结果不是匹配的全部内容,而是组内的内容, ?: 可以让结果为匹配的全部内容
print(re.findall('href="(.*?)"','<a href="http://www.baidu.com"> 点击 </a>'))
# ['http://www.baidu.com']
print(re.findall('href="(?:.*?)"','<a href="http://www.baidu.com"> 点击 </a><a href="http://www.aiqiyi.com"> 点击 2 </a>'))
# ['href="http://www.baidu.com"', 'href="http://www.aiqiyi.com"']
  • a|b : 左右两边都匹配
print(re.findall("shawn|song","shawn is man song is shawn"))  # ['shawn', 'song', 'shawn'] (不加括号全局匹配)
print(re.findall("A(?:abc|cba)A","AabcA"))  # ['AabcA']
print(re.findall("com(?:puter|e)","come on! Here is a computer "))  # ['come', 'computer']
  • \ : 转义字符
# 转义字符,使后一个字符改变原来的意思。# 如果字符串中有字符 * 需要匹配,可以使用 \* 或者字符集 [*]
print(re.findall("a.b","a1b a.b"))   # ['a1b', 'a.b']
print(re.findall("a\.b","a1b a.b"))  # ['a.b']

💠匹配所有数字类型示例

print(re.findall("\d+\.?\d*","12as3.45qw2k7"))  # ['12', '3.45', '2', '7']

💠.* 贪婪匹配示例

  • 匹配更多的字符
print(re.findall("a.*b","a11b22222b33"))  # ['a11b22222b']

💠.*? 非贪婪匹配示例

  • 尽可能少的匹配
print(re.findall("a.*?b","a11b22222b3"))  # ['a11b']

六. re 模块常用方法示例

1、re.findall(pattern,string)

  • 返回所有满足匹配的结果, 按照顺序依次放入列表中, 如果没有匹配结果, 返回一个空列表
print(re.findall("abc","112abc333"))  # ['abc']
print(re.findall("abcd","12abc333"))  # []

2、re.search(pattern,string)

  • 匹配整个字符串, 只到找到 第一个 匹配然后返回一个包含匹配信息的对象(re.Match 对象)
  • 该对象可以通过调用 group() 方法得到匹配的字符串, 如果字符串没有匹配,则返回None
  • 如果没有匹配到值就调用 group() 方法, 抛出异常
print(re.search("abc","112abc333abc"))  
# <re.Match object; span=(3, 6), match='abc'>
print(re.search("abc","112abc333abc").group())  # abc

print(re.search("abcd","12abc333abc"))          # None
print(re.search("abcd","12abc333abc").group()) 
# 报错 "AttributeError" (因为没拿到这个对象, 所以没有 group()属性

3、re.match(pattern,string)

  • re.search 功能相同, 但必须匹配起始位置, 不然返回 None
  • 可以使用上尖号 ^ : re.search("^abc","abc") 实现 re.match() 功能
print(re.match("abc","abc22abc"))  # <re.Match object; span=(0, 3), match='abc'>
print(re.match("abc","abc22abc").group())  # abc

print(re.match("abc","1abc22abc"))  # None
print(re.search("^abc","1abcabc"))  # None  (re.search)

4、re.split(pattern,string)

  • 规定字符 作为分隔符对字符串进行切分, 切分结果放入列表, 没匹配到返回原字符串列表
  • 将规定字符放入 [] 则是逐个匹配
print(re.split("o","abcoabcoabc"))   # ['abc', 'abc', 'abc']
print(re.split("ab","abcoabcoabc"))  # ['','co','co','c']

print(re.split("d","abcoabcoabc"))  # ['abcoabcoabc'] (没匹配到返回原字符串)

print(re.split("[o]","abcoabcoabc"))  # ['abc', 'abc', 'abc']
print(re.split("[ob]","abcoabcoabc"))   # ['a', 'c', 'a', 'c', 'a', 'c']
print(re.split("[oba]","abcoabcoabc"))  # ['','', 'c', '','', 'c', '','', 'c']
# 先使用 "o" 匹配进行分隔, 得到结果 "['abc', 'abc', 'abc']", 在使用 "b" 进行匹配分隔, 得到结果后再使用 "a" 匹配进行分隔

5、re.sub() 和 re.subn()

  • 匹配"规则字符", 并将其改成指定字符, 返回改变后的字符串, 后面可跟数量参数, 不指定默认替换所有
  • re.subn() 返回一个元组, 第二个元素返回的是替换的个数
print(re.sub("a","A","i am a man"))   # i Am A mAn
print(re.sub("a","b","i am a man"))   # i bm b mbn
print(re.sub("am","b","i am a man"))  # i b a man
print(re.sub("a","AA","i am a man"))  # i AAm AA mAAn

print(re.sub("a","A","i am a man",1))  # i Am a man
print(re.sub("a","A","i am a man",2))  # i Am A man
print(re.sub("a","A","i am a man",3))  # i Am A mAn
print(re.sub("a","A","i am a man",9))  # i Am A mAn (超出字符串中最大的个数不会报错, 而是替换所有)

print(re.subn("a","A","i am a man"))    # ('i Am A mAn', 3) (显示替换的个数)
print(re.subn("a","A","i am a man",2))  # ('i Am A man', 2)

6、re.compile()

  • 在该函数中传入"规则字符", 返回一个对象, 它单独使用没有任何意义, 需要和 findall(), search(), match() 组合使用
obj = re.compile("\d{2}")
print(obj)  # re.compile('\\d{2}')

print(obj.findall("ab12c33b44"))         # ['12', '33', '44']
print(obj.search("ab12c33b44").group())  # 12
print(obj.match("12c33b44").group())     # 12 (注意, 必须在开头就匹配到, 不然 group 会报错)

七. 补充非捕获模式 : ?: ?! ?=

字符 描述
(?:pattern) 匹配 pattern,但不捕获匹配结果。
(?=pattern) 零宽度正向预查,不捕获匹配结果。
(?!pattern) 零宽度负向预查,不捕获匹配结果。
(?<=pattern) 零宽度正向回查,不捕获匹配结果。
(?<!pattern) 零宽度负向回查,不捕获匹配结果。

1、?! 示例

  • ?! pattern, 表示在没有配到 pattern 的字符串的前提下,再进行后续的正则表达式匹配,后续匹配仍然从被匹配字符串的头开始
🍓 匹配密码,密码必须是由 6 位数字与字母组成,并且不能是纯数字也不能是纯字母
while 1:
    passwd = input(">>").strip()
    res = re.match("(?![\d]+$)(?![a-zA-Z]+$)[\da-zA-Z]{6}$",passwd)
    if res:
        print(f" 密码:{res.group()}")
    else:
        print(" 密码不符合规则 ")

2、?= 示例

  • ?= pattern, 表示在配到 pattern 的字符串的前提下,再进行后续的正则表达式匹配,后续匹配仍然从被匹配字符串的头开始
🍓 匹配密码,必须包含大写,小写和数字, 和特殊字符(!,@,#,%,&), 且大于 6 位
while 1:
    passwd = input(" 请输入密码 >>").strip()
    res = re.search("(?=.*[\d])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#%&])^([\da-zA-Z!@#%&]{7,})$",passwd)
    if res:
        print(res.group())
    else:
        print(" 密码强度不够 ")
正文完
 
shawn
版权声明:本站原创文章,由 shawn 2023-06-16发表,共计8165字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)